package net.ib.mtalk.service;

import java.util.Date;
import java.util.List;
import java.util.UUID;

import net.ib.mntalk.protocol.Common;
import net.ib.mntalk.protocol.Common.Message;
import net.ib.mntalk.protocol.Common.NotificationInfo;
import net.ib.mntalk.protocol.Common.UUIDMsg;
import net.ib.mntalk.protocol.Common.UUIDSliceRange;
import net.ib.mntalk.protocol.Common.ViewChange;
import net.ib.mntalk.protocol.Common.ViewInfo;
import net.ib.mntalk.protocol.Session.GetMembersReq;
import net.ib.mntalk.protocol.Session.GetViewPropertiesReq;
import net.ib.mntalk.protocol.Session.GetViewPropertiesRes;
import net.ib.mntalk.protocol.Session.GetViewsChangesRes;
import net.ib.mntalk.protocol.Session.GetViewsRes;
import net.ib.mtalk.R;
import net.ib.mtalk.constant.ServiceConstant;
import net.ib.mtalk.database.DatabaseContract.ViewTable;
import net.ib.mtalk.database.helper.InboxDatabaseHelper;
import net.ib.mtalk.global.GlobalPreferences;
import net.ib.mtalk.network.NetResultReceiver;
import net.ib.mtalk.network.TcpEnvelope;
import net.ib.mtalk.network.serverapi.ViewService;
import net.ib.mtalk.network.task.GetMembersTask;
import net.ib.mtalk.ui.chat.ChatListActivity;
import net.ib.mtalk.ui.chat.ChatListBackgroundActivity;
import net.ib.mtalk.ui.inbox.InboxController;
import net.ib.mtalk.ui.inbox.InboxListActivity;
import net.ib.mtalk.util.GpbSupport;
import net.ib.mtalk.util.MTalkLogWriter;
import net.ib.mtalk.util.NotiClient;
import net.ib.mtalk.util.TimeAdapter;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Handler;
import android.util.Log;

public class ViewChangeHandler extends SelectResultHandler {

	// 종료를 위한 수행 카운터
	private int mFinishCount;
	
	private NotificationInfo mNotiInfo;
	private Context mContext;
	private Handler mHandler;
	
	private UUIDMsg viewChangeNotiUuid;
	
	
	/**
	 * 한 개의 NotificationInfo에 대하여 객체가 한 개씩 생성된다.
	 * @param notificationInfo {@link Common#VIEW_CHANGED}에 해당하는 객체
	 */
	ViewChangeHandler(Context context, NotificationInfo notificationInfo) {
		super(context, notificationInfo);
		mNotiInfo = notificationInfo;
		mContext = context;
		mFinishCount = 0;
	}

	@Override
	protected void onWork(Handler handler) {
		MTalkLogWriter.v("ViewChangeHandler.onWork() - STT");

		mHandler = handler;
		
		UUIDSliceRange range = new UUIDSliceRange();
		// 시작점은 이전에 받았던 마지막 노티 타임 UUID
		// 끝점은 방금 통보받은 노티 타임 UUID
		// TODO : 내림 차순으로 변경
		Log.w("ATOM", "Noti UUID Start : " + GpbSupport.UuidMsgToString(GlobalPreferences.getLastViewChangedNotiUuid()));
		Log.w("ATOM", "Noti UUID Start : " + TimeAdapter.Date2Str(new Date(TimeAdapter.getMillisecondFromUUIDMsg(GlobalPreferences.getLastViewChangedNotiUuid())), "yyyy-MM-dd HH:mm:ss"));
		
		Log.w("ATOM", "Noti UUID End   : " + GpbSupport.UuidMsgToString(mNotiInfo.getNotiId().getNotiUuid()));
		Log.w("ATOM", "Noti UUID End   : " + TimeAdapter.Date2Str(new Date(TimeAdapter.getMillisecondFromUUIDMsg(mNotiInfo.getNotiId().getNotiUuid())), "yyyy-MM-dd HH:mm:ss"));
		range.setStart(GlobalPreferences.getLastViewChangedNotiUuid());
		range.setEnd(mNotiInfo.getNotiId().getNotiUuid());
		range.setAscending(true);
		range.setMaxCount(InboxListActivity.GET_VIEWS_COUNT);

		// 알림을 위한 ViewChanges를 요청한다.
		ViewService.getViewChanges(GlobalPreferences.getUserUUID(), range, getCallback());

		MTalkLogWriter.v("ViewChangeHandler.onWork() - END");
	}

	/**
	 * 작업을 끝내 달라.
	 */
	private void finishMyJob() {
		if(mFinishCount <= 1){
			MTalkLogWriter.d("ViewChangeHandler : FINISH()");
			finish();	// 넌 죽었음.
		}else{
			mFinishCount--;
		}
	}
	
	
	private NetResultReceiver mCallback = null;
	
	protected NetResultReceiver getCallback() {
		if(mCallback == null){ 
			mCallback = new NetResultReceiver(mHandler, new ViewChangeCallback());
		}
		return mCallback;
	}
	
	class ViewChangeCallback implements NetResultReceiver.Receiver {

		@Override
		public void onNetResult(int resultCode, Object sentObject,
				Object receivedObject) {
			if (resultCode != NetResultReceiver.TCP_RESULT) {	// 그냥 예외 체크
				MTalkLogWriter.e("ViewChangeHandler.ViewChangeCallback.onNetResult(): Should not reach here. It's not tcp result");
				return;
			}
			try {
				TcpEnvelope recvEnvelope = (TcpEnvelope) receivedObject;
				// 네트워크 결과에 따른 분기
				switch (recvEnvelope.getMethodId()) {
					case net.ib.mtalk.network.MethodId.Session.View.GetViewsChanges:
						if(((GetViewsChangesRes) recvEnvelope.getMessage()).getResponseCode() == Common.EXPIRED_CACHE){
							InboxController controller = new InboxController(mContext, mHandler);
							controller.getAllViews();
							finishMyJob();
						}else{							
							onGetViewsChangesResult((GetViewsChangesRes) recvEnvelope.getMessage());
						}
						break;
					case net.ib.mtalk.network.MethodId.Session.View.GetViews:
						onGetViewsResult((GetViewsRes) recvEnvelope.getMessage());
						break;
					case net.ib.mtalk.network.MethodId.Session.View.GetViewProperties:
						onGetViewProPertiesResult((GetViewPropertiesRes) recvEnvelope.getMessage());
						break;
				}
			} catch (Exception e) {
				finishMyJob();
				
				MTalkLogWriter.e(e);
			}
		}

		@Override
		public void onNetError(int resultCode, Object sentObject) {
			finishMyJob();
		}
	}
	
	/**
	 * ViewsChanges 에 대한 결과 처리
	 * ViewsProperties를 요청한다.
	 * @param viewChangesRes
	 */
	protected void onGetViewsChangesResult(GetViewsChangesRes viewChangesRes) {
		if (viewChangesRes.getResponseCode() != Common.SUCCESS) {	// 서버가 비정상 결과를 돌려줌
			finishMyJob();
			return;
		}
		
		mFinishCount = viewChangesRes.getViewChangeCount();
		if(mFinishCount == 0){
			finishMyJob();
		}
		
		// 변경된 사항에 대해서 properties 를 요청한다.
		for(int i = 0; i < viewChangesRes.getViewChangeCount(); i++){
			ViewChange viewChange = null;
			viewChange = viewChangesRes.getViewChange(i);
			UUIDMsg viewUuid = viewChange.getViewUuid();
			List<Integer> viewPropertyList = viewChange.getPropertyList();
			viewChangeNotiUuid = viewChange.getNotiUuid();
			
			// 변경된 타입별로 분류 // ADDED/REMOVED/MODIFIED
			// NotiUUID는 타입별로 처리가 완전히 끝났을때 설정해준다. (실패할경우 설정하지 않기 위해서)
			switch(viewChange.getType()){
				case Common.ADDED:
					MTalkLogWriter.d("GetViewChageneRes ADDED");
					// GetView 를 호출해서 뷰 정보를 받아 온다.
					// 내부적으로 NotiUUID를 설정한다.
					ViewService.getViews(viewUuid, getCallback());
					
					break;
				case Common.REMOVED:
					// 그냥 지우자! 팍팍팍
					MTalkLogWriter.d("GetViewChageneRes REMOVED");
					InboxDatabaseHelper.deleteView(mContext, viewUuid);
					// NotiUUID 를 설정해준다.
					GlobalPreferences.setLastViewChangedNotiUUID(viewChangeNotiUuid);
					finishMyJob();
					break;
				case Common.MODIFIED:
					// 무언가 변경되었습니다. 변경된 내용을 달라고 해야지!
					MTalkLogWriter.d("GetViewChageneRes MODIFIED");
					GetViewPropertiesReq getViewPropertiesReq = new GetViewPropertiesReq();
					getViewPropertiesReq.setViewUuid(viewUuid);
					MTalkLogWriter.i("viewPropertyList count : " + viewPropertyList.size());
					for(int viewPropertyType : viewPropertyList){
						if(viewPropertyType == Common.TITLE){
							getViewPropertiesReq.addProperty(Common.TITLE);
						}else if(viewPropertyType == Common.LATEST_MESSAGE){
							getViewPropertiesReq.addProperty(Common.LATEST_MESSAGE);
						}else if(viewPropertyType == Common.MEMBER_COUNT){
							getViewPropertiesReq.addProperty(Common.MEMBER_COUNT);
						}else if(viewPropertyType == Common.UNREAD_COUNT){
							getViewPropertiesReq.addProperty(Common.UNREAD_COUNT);
						}
					}
					// 뭐가 바뀐건지 알려주지를 않는다.!!! ㅠㅠ
					// 그냥 전부다 요청해버리자! 
					if(viewPropertyList.size() == 0){
						getViewPropertiesReq.addProperty(Common.TITLE);
						getViewPropertiesReq.addProperty(Common.LATEST_MESSAGE);
						getViewPropertiesReq.addProperty(Common.MEMBER_COUNT);
						getViewPropertiesReq.addProperty(Common.UNREAD_COUNT);
					}
					
					getViewPropertiesReq.addProperty(Common.PUSH_ALLOWED);
					// 내부적으로 NotiUUID를 설정한다.
					ViewService.getViewProperties(getViewPropertiesReq, getCallback());
					break;
			}
		}
	}
	
	/**
	 * GetViewsRes 에 대한 결과 처리.
	 * @param viewsRes
	 */
	protected void onGetViewsResult(GetViewsRes viewsRes){
		if(viewsRes.getResponseCode() == Common.SUCCESS){
			// 내부적으로 NotiUUID를 설정한다.
//			InboxDatabaseHelper.insertSyncView(mContext, viewsRes);
			ViewInfo viewInfo = new ViewInfo();
			for(int i = 0; i < viewsRes.getViewCount(); i++){
				viewInfo = viewsRes.getView(i);
				UUID clientViewUuid = InboxDatabaseHelper.syncView(mContext, viewInfo);
				switch(viewInfo.getType()){
					case Common.BROADCAST:
					case Common.GROUP_CHAT:
						UUIDSliceRange range = new UUIDSliceRange();
						range.setAscending(true);
						range.setMaxCount(ChatListActivity.GET_MEMBER_COUNT);
						
						GetMembersReq getMembersReq = new GetMembersReq();
						getMembersReq.setRange(range);
						getMembersReq.setViewUuid(viewInfo.getViewUuid());
						
						GetMembersTask task = new GetMembersTask(mContext, mHandler, 
								clientViewUuid.getMostSignificantBits(), clientViewUuid.getLeastSignificantBits(), 
								getMembersReq);
						task.execute();
						break;
					case Common.ONE_TO_ONE:
					default:
						break;
				}
				// NotiUUID를 설정해준다.
				if(viewsRes.getView(i).hasLatestMessage()){
					GlobalPreferences.setLastViewChangedNotiUUID(viewsRes.getView(i).getLatestMessage().getNotiUuid());
				}
			}
			MTalkLogWriter.d("onGetViewsResult : SUCCESS");
			if(viewsRes.hasNotiUuid()){
				GlobalPreferences.setLastViewChangedNotiUUID(viewChangeNotiUuid);
			}
			finishMyJob();
		}else{
			finishMyJob();
		}
	}
	
	/**
	 * ViewPropertiesRes 에 대한 결과 처리
	 * @param viewPropertiesRes
	 */
	protected void onGetViewProPertiesResult(GetViewPropertiesRes viewPropertiesRes){

		// 결과가 정상인지 체크한다.
		if(viewPropertiesRes.getResponseCode() == Common.SUCCESS){
			MTalkLogWriter.d("onGetViewProPertiesResult : SUCCESS");
			// TODO : 디비작업
			ViewInfo viewInfo = viewPropertiesRes.getView();
			// ViewUUID 에 대한 Client 뷰를 확인(생성/업데이트) 한다.
			UUID clientViewUuid = InboxDatabaseHelper.syncView(mContext, viewInfo);

			// 변경된 메시지가 있고, 변경된 유저메시지가 있을때! 알려주자!
			/**
			 * Noti를 띄워주는 부분!!
			 */
			// unsubscribe 상태이면 true!!
			boolean unsubscribe = true;
			if(GlobalPreferences.subscribeView != null){
				if((GpbSupport.msbOf(GlobalPreferences.subscribeView) == GpbSupport.msbOf(viewInfo.getViewUuid()))
				&& (GpbSupport.lsbOf(GlobalPreferences.subscribeView) == GpbSupport.lsbOf(viewInfo.getViewUuid()))){
					unsubscribe =  false;
				}else{
					unsubscribe = true;
				}
			}else{
				unsubscribe = true;
			}
			
			if(viewInfo.hasLatestMessage() 
					&& viewInfo.getLatestMessage().hasUserMassage()
					&& viewInfo.getLatestMessage().getType() == Common.MSG_TYPE_USER_MSG
					&& ((GpbSupport.msbOf(viewInfo.getLatestMessage().getUserMassage().getSenderUuid()) != GpbSupport.msbOf(GlobalPreferences.getUserUUID()))
					|| (GpbSupport.lsbOf(viewInfo.getLatestMessage().getUserMassage().getSenderUuid()) != GpbSupport.lsbOf(GlobalPreferences.getUserUUID())))
					&& unsubscribe
					&& GlobalPreferences.getBooleanNoti(mContext)
					&& viewInfo.hasPushAllowed()
					&& viewInfo.getPushAllowed() == true){
				Message latestMessage = new Message();
				latestMessage = viewInfo.getLatestMessage();
	
				// 노티에 넣을 정보를 정리해보자.
				String notiMainText = "";
				String viewTitle = "";
				switch(viewInfo.getType()){
					case Common.ONE_TO_ONE:
						if(GlobalPreferences.getBooleanShowSender(mContext)){
							viewTitle = viewInfo.getTitle();
						}else{
							viewTitle = mContext.getString(R.string.inbox_chat_title);
						}
						break;
					case Common.BROADCAST:
					case Common.GROUP_CHAT:
					default:
						viewTitle = viewInfo.getTitle();
						break;
				}

				if(GlobalPreferences.getBooleanShowMessage(mContext)){
					// 노티 메인텍스트 추출
					Common.UserMessage userMsg = latestMessage.getUserMassage();
					notiMainText += userMsg.getContent();
				}else{
					notiMainText += mContext.getString(R.string.noti_new_msg);
				}

				// 인텐트를 만든다.
				Intent intent = new Intent(mContext, ChatListBackgroundActivity.class);
				/*intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
						| Intent.FLAG_ACTIVITY_CLEAR_TOP
						| Intent.FLAG_ACTIVITY_SINGLE_TOP);*/
				intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
				intent.putExtra(ChatListActivity.INTENT_ENABLE, ViewTable.EnableType.ENABLE.ordinal());
				intent.putExtra(ChatListActivity.INTENT_EXIST_VIEW, true);
				intent.putExtra(ChatListActivity.INTENT_CLIENT_VIEW_MSB, clientViewUuid.getMostSignificantBits());
				intent.putExtra(ChatListActivity.INTENT_CLIENT_VIEW_LSB, clientViewUuid.getLeastSignificantBits());
				PendingIntent pendingIntent = PendingIntent.getActivity(mContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
				/**
				 * notification을 중계하는 객체. notification 관련 요청은 이 객체를 통해 이루어진다.
				 */
				NotiClient notiClient = new NotiClient(mContext);

				// 노티를 보여주자
				android.app.Notification noti = new android.app.Notification(R.drawable.noti, mContext.getString(R.string.noti_new_msg), 0);
				noti.flags = noti.flags | android.app.Notification.FLAG_AUTO_CANCEL;
				noti.setLatestEventInfo(mContext, notiMainText, viewTitle, pendingIntent);
				// 진동 설정
				if(GlobalPreferences.getBooleanVibrate(mContext)){
					long[] pattern = {100, 200, 100, 200, 100, 200};
					noti.vibrate = pattern;
				}
				// 벨소리 설정
				if(GlobalPreferences.getStringRingtone(mContext) != null){
					noti.sound = Uri.parse(GlobalPreferences.getStringRingtone(mContext));
				}
				
				notiClient.showNoti(ServiceConstant.NOTI_ID_MSG_RECV, noti);

			}
			// NotiUUID 를 설정해준다.
			GlobalPreferences.setLastViewChangedNotiUUID(viewChangeNotiUuid);
			finishMyJob();
		} else{
			finishMyJob();
		}
	}
}
